/**************************************************************************
*
* Tint Task Manager
* 
* Copyright (C) 2007 Pål Staurland (staura@gmail.com)
* 
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Soft-
* ware"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, subject to the following condi-
* tions:
* 
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
* ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* 
**************************************************************************/

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "task.h"
#include "server.h"
#include "window.h"
#include "config.h"

void add_task (Window win)
{
	Task *new_tsk, *tsk;

	if (!win ||
		window_is_hidden (win) || 
		win == window.main_win ||
		window_get_desktop (win) != server.desktop)
		return;
		
	new_tsk = calloc(1, sizeof(Task));
	new_tsk->icon_data = 0;
	new_tsk->pmap = new_tsk->active_pmap = 0;
	new_tsk->win = win;
	window_get_icon (new_tsk);
	new_tsk->title = server_get_property (win, server.atom._NET_WM_VISIBLE_NAME, server.atom.UTF8_STRING, 0);
	new_tsk->active = window_is_active (new_tsk->win);
	new_tsk->iconified = window_is_iconified (new_tsk->win);
	new_tsk->desktop = window_get_desktop (new_tsk->win);
	new_tsk->width = config.task_width;
	new_tsk->height = config.panel_height - (config.task_margin * 2);
	XSelectInput (server.dsp, new_tsk->win, PropertyChangeMask|StructureNotifyMask); 
	new_tsk->need_refresh = 1;
	
	/* Append */
	task.task_count++;
	tsk = task.tasklist;
	if (!tsk)
	{
		task.tasklist = new_tsk;
		return;
	}
	while (1)
	{
		if (!tsk->next)
		{
			tsk->next = new_tsk;
			return;
		}
		tsk = tsk->next;
	}
}

Task *task_get_task (Window win)
{
	Task *tsk;
	tsk = task.tasklist;
	while (tsk)
	{
		if (win == tsk->win)
			return tsk;
	
		tsk = tsk->next;
	}
	return 0;
}

void task_refresh_tasklist ()
{
	Task *tsk, *next;
	Window *win, active_win;
	int num_results, i, dontdel;

	win = server_get_property (server.root_win, server.atom._NET_CLIENT_LIST, XA_WINDOW, &num_results);
	
	if (!win)
		return;

	/* Remove any old */
	tsk = task.tasklist;
	while (tsk)
	{
		dontdel = 0;
		next = tsk->next;
		for (i = 0; i < num_results; i++)
		{
			if (tsk->win == win[i])
				dontdel = 1;
		}
		if (!dontdel)
			task_remove_task (tsk->win);
		
		tsk = next;
	}
	
	/* Add any new */
	for (i = 0; i < num_results; i++)
	{
		if (!task_get_task (win[i]))
			add_task (win[i]);
	}
	
	/* Set active win */
	active_win = window_get_active ();
	tsk = task.tasklist;
	while (tsk)
	{
		tsk->active = 0;
		if (tsk->win == active_win)
			tsk->active = 1;
		tsk = tsk->next;
	}

	XFree (win);
}

void task_new_desktop ()
{
	Task *tsk, *next;
	
	server.desktop = server_get_current_desktop ();
	
	/* Remove tasks that's not on this desktop */
	tsk = task.tasklist;
	while (tsk)
	{
		next = tsk->next;
		if (tsk->desktop != server.desktop)
			task_remove_task (tsk->win);
		tsk = next;
	}
}

void task_remove_task (Window win)
{
	Task *t, *n, *p;
	t = task.tasklist;
	p = 0;
	
	while (t)
	{
		n = t->next;
		if (t->win == win)
		{
			task.task_count--;
			
			if (t->title)
				XFree (t->title);
			if (t->icon_data != 0)
				XFree (t->icon_data);
			XFreePixmap (server.dsp, t->pmap);
			XFreePixmap (server.dsp, t->active_pmap);
			free(t);
			
			if (!p)
				task.tasklist = n;
			else
				p->next = n;
			return;
		}
		p = t;
		t = n;
	}
}


